package com.easylinkin.linkappapi.progress.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.NumberUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.additional.update.impl.LambdaUpdateChainWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.easylinkin.linkappapi.common.service.CommonService;
import com.easylinkin.linkappapi.progress.entity.ProgressInfo;
import com.easylinkin.linkappapi.progress.entity.ProgressIntegrateRef;
import com.easylinkin.linkappapi.progress.entity.ProgressRealDetail;
//import com.easylinkin.linkappapi.progress.entity.dto.BimIntegrateProgressDTO;
import com.easylinkin.linkappapi.progress.entity.dto.ProgressRealDTO;
import com.easylinkin.linkappapi.progress.entity.dto.ProgressRealDetailDTO;
import com.easylinkin.linkappapi.progress.entity.vo.ProgressInfoVo;
import com.easylinkin.linkappapi.progress.entity.vo.ProgressRealDetailVo;
import com.easylinkin.linkappapi.progress.entity.vo.TaskRealProgressVo;
import com.easylinkin.linkappapi.progress.mapper.ProgressInfoMapper;
import com.easylinkin.linkappapi.progress.mapper.ProgressIntegrateRefMapper;
import com.easylinkin.linkappapi.progress.mapper.ProgressRealDetailMapper;
import com.easylinkin.linkappapi.progress.service.ProgressInfoService;
import com.easylinkin.linkappapi.progress.service.ProgressRealDetailService;
import com.easylinkin.linkappapi.security.context.LinkappUserContextProducer;
import com.easylinkin.linkappapi.security.entity.LinkappUser;
import com.easylinkin.linkappapi.security.mapper.LinkappUserMapper;
//import com.easylinkin.linkappapi.systemsettings.mapper.BimIntegrateItemMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import site.morn.rest.RestBuilders;
import site.morn.rest.RestMessage;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.Serializable;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * ProgressRealDetail表服务实现类
 *
 * @author zhengwen
 * @date 2023/11/20
 */
@Slf4j
@Service("appProgressRealDetailService")
public class ProgressRealDetailServiceImpl extends ServiceImpl
        <ProgressRealDetailMapper, ProgressRealDetail> implements ProgressRealDetailService {
    @Resource
    private ProgressInfoService progressInfoService;
    @Resource
    private CommonService commonService;

    @Resource
    private LinkappUserContextProducer linkappUserContextProducer;

    @Resource
    private LinkappUserMapper linkappUserMapper;

    @Resource
    private ProgressInfoMapper progressInfoMapper;

    @Resource
    private ProgressIntegrateRefMapper progressIntegrateRefMapper;

//    @Resource
//    private BimIntegrateItemMapper bimIntegrateItemMapper;

    @Override
    public boolean removeById(Serializable id) {
        return super.update().set("deleted_", id).eq("id_", id).update();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteByIds(List<Long> idList) {
        // 将删除状态改为主键值
        new LambdaUpdateChainWrapper<>(getBaseMapper()).setSql("deleted_ = id_").in(ProgressRealDetail::getId, idList).update();
        return true;
    }


    @Override
    public boolean saveOne(ProgressRealDetail appProgressRealDetail) {
        commonService.setCreateAndModifyInfo(appProgressRealDetail);

        validParamRequired(appProgressRealDetail);
        validRepeat(appProgressRealDetail);
        validParamFormat(appProgressRealDetail);
        return save(appProgressRealDetail);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateOne(ProgressRealDetail appProgressRealDetail) {
        Assert.notNull(appProgressRealDetail.getId(), "id不能为空");
        commonService.setModifyInfo(appProgressRealDetail);

        validRepeat(appProgressRealDetail);
        validParamFormat(appProgressRealDetail);
        return updateById(appProgressRealDetail);
    }

    @Override
    public IPage<ProgressRealDetail> selectPage(Page page, ProgressRealDetail appProgressRealDetail) {
        return baseMapper.selectPage(page, appProgressRealDetail);
    }

    @Override
    public void export(ProgressRealDetail appProgressRealDetail, HttpServletRequest request, HttpServletResponse
            response) {

    }

    @Override
    public RestMessage getDtoPage(Page page, ProgressRealDetailVo progressRealDetailVo) {
        ProgressInfo progressInfo = progressRealDetailVo.getProgressInfo();
        Assert.notNull(progressInfo, "progressInfo 不能为空");
//        Assert.notNull(progressInfo.getId(), "进度计划id不能为空");

        //查询进度计划
        ProgressInfo progressPlan = null;
        if (progressInfo.getId() == null){
            //查询总计划
            LambdaQueryWrapper<ProgressInfo> progressQw = new LambdaQueryWrapper<>();
            progressQw.eq(ProgressInfo::getTenantId, linkappUserContextProducer.getNotNullCurrent().getTenantId());
            progressQw.eq(ProgressInfo::getName, progressInfo.getName());
            List<ProgressInfo> progressInfos = progressInfoMapper.selectList(progressQw);
            if (CollectionUtil.isNotEmpty(progressInfos)){
                progressPlan = progressInfos.get(0);
            }
        }else {
            progressPlan = progressInfoMapper.selectById(progressInfo.getId());
//            Assert.notNull(progressPlan, "进度计划不存在");
        }
        if (progressPlan == null){
            return RestBuilders.successBuilder().data(new Page()).build();
        }
        //查询进度计划下的末级任务(这里直接查询末级，再级连查询父级，其实还有2个思路，一个是查所有再剔除，一个是还是查末级，父级值查询一次转map，拼接处理)
        progressRealDetailVo.getProgressInfo().setTenantId(progressPlan.getTenantId());
        progressRealDetailVo.getProgressInfo().setParentIds(progressPlan.getParentIds() + progressPlan.getId() + ",");

        IPage<ProgressRealDTO> iPage = baseMapper.getDtoPage(page, progressRealDetailVo);
        List<ProgressRealDTO> progressRealDTOList = iPage.getRecords();
        if (CollectionUtil.isNotEmpty(progressRealDTOList)) {
            //记录人id
            List<String> userIdList = new ArrayList<>();
            progressRealDTOList.forEach(progressRealDTO -> {
                //计算详情数据
                calDetailData(progressRealDTO,userIdList);
                //处理父级
                dealParentPath(progressRealDTO, progressInfo.getId());
            });
            //处理记录人
            Map<Long,LinkappUser> detailUserMap = queryUserTansMap(userIdList);
            creatorNameSet(progressRealDTOList,detailUserMap);

            //转树形结构是为了顺序
            List<Tree<Long>> build = TreeUtil.build(progressRealDTOList, progressInfo.getId(), (treeNode, tree) -> {
                tree.setId(treeNode.getId());
                tree.setParentId(treeNode.getParentId());
                tree.setName(treeNode.getName());
                tree.setWeight(treeNode.getCreateTime());
                tree.putExtra("progressRealDTO", treeNode);
            });

            //progressRealDTOList排序按照build的id排序
            List<ProgressRealDTO> sortList = new ArrayList<>();
            build.forEach(tree -> {
                addToList(tree,sortList);
            });
            iPage.setRecords(sortList);
        }

        return RestBuilders.successBuilder().data(iPage).build();
    }

    private void addToList(Tree<Long> tree, List<ProgressRealDTO> sortList) {
        ProgressRealDTO progressRealDTO = (ProgressRealDTO) tree.get("progressRealDTO");
        Integer isParent = progressRealDTO.getIsParent();
        if (isParent == 0){
            sortList.add(progressRealDTO);
        }else {
            List<Tree<Long>> children = tree.getChildren();
            if (CollectionUtil.isNotEmpty(children)) {
                children.forEach(child -> {
                    addToList(child, sortList);
                });
            }
        }
    }

    /**
     * 处理实际进度列表记录人
     * @param progressRealDTOList 实际进度列表
     * @param detailUserMap 记录人map
     */
    private void creatorNameSet(List<ProgressRealDTO> progressRealDTOList, Map<Long, LinkappUser> detailUserMap) {
        if (CollectionUtil.isNotEmpty(progressRealDTOList) && CollectionUtil.isNotEmpty(detailUserMap)){
            progressRealDTOList.forEach(progressRealDTO -> {
                if (progressRealDTO != null){
                    String detailCreator = progressRealDTO.getDetailCreator();
                    if (StringUtils.isNotBlank(detailCreator)){
                        LinkappUser user = detailUserMap.get(Long.parseLong(detailCreator));
                        if (user != null){
                            progressRealDTO.setDetailCreatorName(user.getNickname());
                        }
                    }
                }
            });
        }
    }

    private void dealParentPath(ProgressRealDTO progressRealDTO, Long planProgressId) {
        List<ProgressInfo> parentProgressList = progressRealDTO.getParentProgressList();
        if (CollectionUtil.isNotEmpty(parentProgressList)) {
            //父级进度名称
            StringJoiner sj = new StringJoiner("/");
            parentProgressList.forEach(parentTask -> {
                if (parentTask != null) {
                    String parentName = parentTask.getName();
                    if (StringUtils.isNotBlank(parentName)) {
                        sj.add(parentName);
                    }
                    if (parentTask.getParentId().equals(planProgressId)) {
                        //一级进度创建时间
                        progressRealDTO.setFirstCreateTime(parentTask.getCreateTime());
                    }
                }
            });
            progressRealDTO.setParentTaskName(sj.toString());
        }
    }

    @Override
    public RestMessage addRealDetail(ProgressRealDetailVo progressRealDetailVo) {
        Assert.notNull(progressRealDetailVo, "progressRealDetailVo 不能为空");

        //参数转换
        ProgressRealDetail progressRealDetail = new ProgressRealDetail();
        BeanUtil.copyProperties(progressRealDetailVo, progressRealDetail, CopyOptions.create().ignoreNullValue());

        //参数校验
        validParamRequired(progressRealDetail);

        //查询记得计划任务
        ProgressInfo progressTask = progressInfoMapper.selectById(progressRealDetailVo.getProgressTaskId());
        Assert.notNull(progressTask, "进度计划任务不存在");

        //查询实际进度详情
        QueryWrapper<ProgressRealDetail> detailQw = new QueryWrapper<>();
        detailQw.eq("progress_task_id_", progressTask.getId());
        detailQw.select("sum(percentage) as percentage");
        ProgressRealDetail totalPercentageDetail = baseMapper.selectOne(detailQw);
        double totalProgress = totalPercentageDetail == null ? 0.0 : totalPercentageDetail.getPercentage();
        //计算剩余进度
        double remainProgress = NumberUtil.sub(100.0, totalProgress);
        int compare = NumberUtil.compare(progressRealDetail.getPercentage(), remainProgress);
        Assert.isTrue(compare <= 0, "进度百分比超出剩余进度");

        //保存实际进度详情
        commonService.setCreateAndModifyInfo(progressRealDetail);
        save(progressRealDetail);

        return RestBuilders.successBuilder().data(progressRealDetail).build();
    }

    @Override
    public RestMessage realDetail(Long id) {
        //查询实际进度详情
        ProgressInfo progressTask = progressInfoMapper.selectById(id);
        Assert.notNull(progressTask, "进度计划任务不存在");

        //任务详情
        TaskRealProgressVo taskRealProgressVo = new TaskRealProgressVo();
        BeanUtil.copyProperties(progressTask, taskRealProgressVo, CopyOptions.create().ignoreNullValue());

        List<ProgressRealDetailDTO> progressRealDetailDTOList = new ArrayList<>();
        //查询实际进度详情
        QueryWrapper<ProgressRealDetail> detailQw = new QueryWrapper<>();
        detailQw.eq("progress_task_id_", progressTask.getId());
        detailQw.orderByDesc("create_time_");
        List<ProgressRealDetail> detailList = baseMapper.selectList(detailQw);
        if (CollectionUtil.isNotEmpty(detailList)) {
            //detailList里创建人id转list，并去重
            List<String> userIdList = detailList.stream().map(ProgressRealDetail::getCreator).distinct().collect(Collectors.toList());
            //查询用户信息
            Map<Long, LinkappUser> userMap = queryUserTansMap(userIdList);
            detailList.forEach(detail -> {
                ProgressRealDetailDTO dto = new ProgressRealDetailDTO();
                BeanUtil.copyProperties(detail, dto, CopyOptions.create().ignoreNullValue());
                //处理创建人
                String creator = detail.getCreator();
                if (StringUtils.isNotBlank(creator)) {
                    LinkappUser user = userMap.get(Long.parseLong(creator));
                    if (user != null) {
                        dto.setCreatorName(user.getNickname());
                    }
                }
                progressRealDetailDTOList.add(dto);
            });
        }
        //设置实际进度详情list
        taskRealProgressVo.setProgressRealDetailList(progressRealDetailDTOList);

        //关联构建数量
        QueryWrapper<ProgressIntegrateRef> integrateRefQw = new QueryWrapper<>();
        integrateRefQw.eq("progress_id_", progressTask.getId());
        int integrateCount = progressIntegrateRefMapper.selectCount(integrateRefQw);
        taskRealProgressVo.setJoinModelNum(integrateCount);

        return RestBuilders.successBuilder().data(taskRealProgressVo).build();
    }

//    @Override
//    public IPage<BimIntegrateProgressDTO> screenRealProgressIntegrateList(Page page, ProgressInfoVo progressInfoVo) {
//        LinkappUser linkappUser = linkappUserContextProducer.getCurrent();
//        Assert.notNull(linkappUser, "用户登录信息不存在");
//        String tenantId = linkappUser.getTenantId();
//        Assert.notNull(tenantId, "用户租户id不存在");
//
//        progressInfoVo.setTenantId(tenantId);
//        if (progressInfoVo.getType() == null){
//            progressInfoVo.setType(2);
//        }
//        //20231213变更逻辑：只查询总计划的实际进度
//        if (progressInfoVo.getPlanType() != null){
//            //查询总计划
//            QueryWrapper<ProgressInfo> progressQw = new QueryWrapper<>();
//            progressQw.eq("tenant_id_", tenantId);
//            progressQw.eq("type_", 1);
//            progressQw.eq("plan_type_", progressInfoVo.getPlanType());
//            ProgressInfo progressInfo = progressInfoMapper.selectOne(progressQw);
//            if (progressInfo != null){
//                progressInfoVo.setPlanType(null);
//                progressInfoVo.setParentIds(progressInfo.getParentIds() + progressInfo.getId() + ",");
//            }
//        }
//
//        IPage<BimIntegrateProgressDTO> iPage = bimIntegrateItemMapper.screenRealProgressIntegrateList(page, progressInfoVo);
//
//        return iPage;
//    }

    private Map<Long, LinkappUser> queryUserTansMap(List<String> userIdList) {
        Map<Long, LinkappUser> userMap = Collections.emptyMap();
        if (CollectionUtil.isNotEmpty(userIdList)) {
            List<LinkappUser> userList = linkappUserMapper.selectBatchIds(userIdList);
            if (CollectionUtil.isNotEmpty(userList)) {
                userMap = userList.stream().collect(Collectors.toMap(LinkappUser::getId, user -> user));
            }
        }
        return userMap;
    }

    /**
     * 计算详情数据
     *
     * @param progressRealDTO 实际进度DTO
     * @param userIdList
     */
    private void calDetailData(ProgressRealDTO progressRealDTO, List<String> userIdList) {
        if (progressRealDTO != null) {
            List<ProgressRealDetail> detailList = progressRealDTO.getProgressRealDetailList();
            //进度未开始
            progressRealDTO.setEndState(0);
            //风险判断
            Date planStartTime = DateUtil.beginOfDay(progressRealDTO.getStartTime());
            Date now = DateUtil.beginOfDay(DateUtil.date());
            if (planStartTime.before(now)) {
                progressRealDTO.setHasRisk(true);
            } else {
                progressRealDTO.setHasRisk(false);
            }

            if (CollectionUtil.isNotEmpty(detailList)) {

                final Double[] totalProgress = {0.0};
                final Date[] lastCreateTime = {null};
                AtomicReference<String> detailCreator = new AtomicReference<>();
                detailList.forEach(detail -> {
                    if (detail != null) {
                        //记录人
                        if (lastCreateTime[0] == null){
                            lastCreateTime[0] = detail.getCreateTime();
                            detailCreator.set(detail.getCreator());
                        }else {
                            if (detail.getCreateTime() != null && detail.getCreateTime().after(lastCreateTime[0])){
                                lastCreateTime[0] = detail.getCreateTime();
                                detailCreator.set(detail.getCreator());
                            }
                        }

                        //处理实际开始、结束时间
                        if (progressRealDTO.getRealStartTime() == null) {
                            progressRealDTO.setRealStartTime(detail.getRealStartTime());
                        } else {
                            if (detail.getRealStartTime() != null && detail.getRealStartTime().before(progressRealDTO.getRealStartTime())) {
                                progressRealDTO.setRealStartTime(detail.getRealStartTime());
                            }
                        }
                        if (progressRealDTO.getRealEndTime() == null) {
                            progressRealDTO.setRealEndTime(detail.getRealEndTime());
                        } else {
                            if (detail.getRealEndTime() != null && detail.getRealEndTime().after(progressRealDTO.getRealEndTime())) {
                                progressRealDTO.setRealEndTime(detail.getRealEndTime());
                            }
                        }
                        //进度求和
                        if (detail.getPercentage() != null) {
                            totalProgress[0] = NumberUtil.add(totalProgress[0], detail.getPercentage());
                        }

                    }
                });
                //记录人
                if (StringUtils.isNotBlank(detailCreator.get())){
                    userIdList.add(detailCreator.get());
                    progressRealDTO.setDetailCreator(detailCreator.get());
                }

                //进度之和
                progressRealDTO.setPercentage(totalProgress[0]);

                //完成状态
                Integer compare = NumberUtil.compare(totalProgress[0], 100.0);
                switch (compare) {
                    case -1:
                        progressRealDTO.setEndState(1);
                        break;
                    case 0:
                        progressRealDTO.setEndState(2);
                        break;
                    case 1:
                        progressRealDTO.setEndState(2);
                        break;
                    default:
                        break;
                }
                //风险判断
                //已完成百分比为100%,无任务风险
                Double percentage = progressRealDTO.getPercentage();
                if (percentage != null && percentage >= 100.0) {
                    progressRealDTO.setHasRisk(false);
                } else {
                    //针对百分比小于100%的任务
                    //实际工期 = 实际结束时间 - 实际开始时间 + 1
                    long realWork = DateUtil.betweenDay(progressRealDTO.getRealStartTime(), progressRealDTO.getRealEndTime(), true) + 1;
                    //计划工期
                    long planWork = progressRealDTO.getTotalWork();
                    if (progressRealDTO.getRealStartTime().before(progressRealDTO.getStartTime())) {
                        //实际开始时间早于计划开始时间 (实际工期/计划工期*100%)与完成进度百分比比较
                        double workComp = NumberUtil.div(realWork, planWork);
                        int workCompInt = NumberUtil.compare(NumberUtil.mul(workComp,100), totalProgress[0]);
                        if (workCompInt <= 0) {
                            //工期百分比小于等于完成进度百分比
                            progressRealDTO.setHasRisk(false);
                        } else {
                            progressRealDTO.setHasRisk(true);
                        }
                    } else {
                        //实际开始时间晚于计划开始时间 (实际工期/计划工期*100%)与完成进度百分比比较
                        double workComp = NumberUtil.div(realWork, planWork);
                        int workCompInt = NumberUtil.compare(NumberUtil.mul(workComp,100), totalProgress[0]);
                        if (workCompInt <= 0) {
                            //工期百分比小于等于完成进度百分比
                            progressRealDTO.setHasRisk(false);
                        } else {
                            progressRealDTO.setHasRisk(true);
                        }
                    }
                }

            }
        }
    }

    @Override
    public ProgressRealDetail getOneById(Serializable id) {
        return baseMapper.getOneById(id);
    }

    /**
     * 校验重复
     */
    private void validRepeat(ProgressRealDetail appProgressRealDetail) {

        /* List<ProgressRealDetail> list = new LambdaQueryChainWrapper<>(baseMapper)
            .eq(ProgressRealDetail::getDeviceCode, appProgressRealDetail.getDeviceCode())
            .list();
            if (list.size() > 0 && (list.size() > 1 || ObjectUtils.isEmpty(appProgressRealDetail.getId()) || !appProgressRealDetail.getId().equals(list.get(0).getId()))) {
                throw new BusinessException("名称重复");
            }
        */


    }


    /**
     * 校验参数必填
     */
    private void validParamRequired(ProgressRealDetail appProgressRealDetail) {
        Assert.notNull(appProgressRealDetail, "参数为空");
        //Assert.isTrue(StringUtils.isNotBlank(appProgressRealDetail.getName()), "名称为空");
        Assert.notNull(appProgressRealDetail.getProgressTaskId(), "进度计划任务id为空");
        Assert.notNull(appProgressRealDetail.getRealStartTime(), "实际开始时间为空");
        Assert.notNull(appProgressRealDetail.getRealEndTime(), "实际结束时间为空");
        Assert.notNull(appProgressRealDetail.getPercentage(), "进度百分比为空");
        Assert.isTrue(appProgressRealDetail.getPercentage() >= 0 && appProgressRealDetail.getPercentage() <= 100, "进度百分比不在范围内");
        Assert.isTrue(appProgressRealDetail.getRealStartTime().before(appProgressRealDetail.getRealEndTime()), "实际开始时间晚于实际结束时间");
    }

    /**
     * 校验参数格式
     */
    private void validParamFormat(ProgressRealDetail appProgressRealDetail) {
        //Assert.isTrue(appProgressRealDetail.getName() == null || appProgressRealDetail.getName().length() <= 50,
        //        "名称超长");
    }
}

